#ifndef _GWBASE_AES_HELPER_H_
#define _GWBASE_AES_HELPER_H_

#include <string>
#include <openssl/evp.h>
#include <gwbase/base/util.h>
#include "gwbase/byte_array.h"
#include "gwbase/stopping_flag.h"
#include "gwbase/encrypt/compress_helper.h"

namespace dicom {

class IStoppingFlag;

class Aes256Encrypt {
 public:
  Aes256Encrypt(const ByteArray &key, size_t block_size);
  virtual ~Aes256Encrypt();

  bool Update(const uint8_t *data, size_t inlen);
  bool Finalize();

  const uint8_t *data() { return out_; }
  const uint8_t *end() { return out_ + outlen_; }
  int len() { return outlen_; }

 private:
  EVP_CIPHER_CTX *ctx_;
  size_t block_size_;
  uint8_t *out_;
  int outlen_;
};

class Aes256Decrypt {
 public:
  Aes256Decrypt(const ByteArray &key, size_t block_size);
  virtual ~Aes256Decrypt();

  virtual bool Update(const uint8_t *data, size_t inlen);
  virtual bool Finalize();

  const uint8_t *data() { return out_; }
  const uint8_t *end() { return out_ + outlen_; }
  int len() { return outlen_; }

 private:
  EVP_CIPHER_CTX *ctx_;
  size_t block_size_;
  uint8_t *out_;
  int outlen_;
};

class Aes128Encrypt {
 public:
  Aes128Encrypt(const ByteArray &key, size_t block_size);
  virtual ~Aes128Encrypt();

  bool Update(const uint8_t *data, size_t inlen);
  bool Finalize();

  const uint8_t *data() { return out_; }
  const uint8_t *end() { return out_ + outlen_; }
  int len() { return outlen_; }

 private:
  EVP_CIPHER_CTX *ctx_;
  size_t block_size_;
  uint8_t *out_;
  int outlen_;
};

class Aes128Decrypt {
 public:
  Aes128Decrypt(const ByteArray &key, size_t block_size);
  virtual ~Aes128Decrypt();

  virtual bool Update(const uint8_t *data, size_t inlen);
  virtual bool Finalize();

  const uint8_t *data() { return out_; }
  const uint8_t *end() { return out_ + outlen_; }
  int len() { return outlen_; }

 private:
  EVP_CIPHER_CTX *ctx_;
  size_t block_size_;
  uint8_t *out_;
  int outlen_;
};

enum AesMode {
  kAes128 = 128,
  kAes256 = 256,
};

class AESHelper {
 public:
  static ByteArray Encrypt256(const ByteArray &key, const ByteArray &plain);
  static ByteArray Encrypt128(const ByteArray &key, const ByteArray &plain);

  static ByteArray Decrypt256(const ByteArray &key, const ByteArray &cipher);
  static ByteArray Decrypt128(const ByteArray &key, const ByteArray &cipher);

  static Status EncFile(const ByteArray &key, const std::string &in,
                        const std::string &out, IStoppingFlag *stop = NULL);
  static Status DecFile(const ByteArray &key, const std::string &in,
                        const std::string &out, IStoppingFlag *stop = NULL);

  // 解密并解压缩文件，AES256解密+Deflate解压
  static Status DecAndUncompressFile(const ByteArray &key,
                                     const std::string &in,
                                     const std::string &out,
                                     IStoppingFlag *stop = NULL);
  static Status CompressAndEncFile(const ByteArray &key, const std::string &in,
                                   const std::string &out,
                                   std::string *enc_sha1, std::string *src_md5,
                                   IStoppingFlag *stop = NULL);

  static ByteArray DecryptPrivateKey(const std::string &plain_pwd,
                                     const ByteArray &pk_cipher);
  static ByteArray EncryptPrivateKey(const std::string &plain_pwd,
                                     const ByteArray &pk_plain);
};
}

#endif  // _GWBASE_AES_HELPER_H_
